package com.yaowk.sfp.common.tio;

import com.yaowk.sfp.common.utils.SpringUtils;
import org.tio.core.ChannelContext;
import org.tio.core.GroupContext;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.AioHandler;
import org.tio.core.intf.Packet;

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 小凯
 */
public abstract class BaseAioHandler implements AioHandler {

    private final Map<Byte, IBaseHandler> handlerMap = new HashMap<>();

    public Map<Byte, IBaseHandler> getHandlerMap() {
        return handlerMap;
    }

    protected BaseAioHandler() {
        if (SpringUtils.getApplicationContext() == null) {
            return;
        }
        Map<String, IBaseHandler> beansOfType = SpringUtils.getApplicationContext().getBeansOfType(IBaseHandler.class);
        Set<Map.Entry<String, IBaseHandler>> entries = beansOfType.entrySet();
        for (Map.Entry<String, IBaseHandler> entry : entries) {
            IBaseHandler handler = entry.getValue();
            handlerMap.put(handler.getHandlerType(), handler);
        }
    }

    /**
     * 解码：把接收到的ByteBuffer，解码成应用可以识别的业务消息包
     * 消息头：type + bodyLength
     * 消息体：byte[]
     */
    @Override
    public BasePacket decode(ByteBuffer buffer, ChannelContext channelContext) throws AioDecodeException {
        int readableLength = buffer.limit() - buffer.position();
        if (readableLength < BasePacket.HEADER_LENGTH) {
            return null;
        }

        //消息类型
        byte type = buffer.get();

        int bodyLength = buffer.getInt();

        if (bodyLength < 0) {
            throw new AioDecodeException("bodyLength [" + bodyLength + "] is not right, remote:" + channelContext.getClientNode());
        }

        int neededLength = BasePacket.HEADER_LENGTH + bodyLength;
        int test = readableLength - neededLength;
        // 不够消息体长度(剩下的buffe组不了消息体)
        if (test < 0) {
            return null;
        } else {
            BasePacket imPacket = new BasePacket();
            imPacket.setType(type);
            if (bodyLength > 0) {
                byte[] dst = new byte[bodyLength];
                buffer.get(dst);
                imPacket.setBody(dst);
            }
            return imPacket;
        }
    }

    /**
     * 编码：把业务消息包编码为可以发送的ByteBuffer
     * 消息头：type + bodyLength
     * 消息体：byte[]
     */
    @Override
    public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) {
        BasePacket basePacket = (BasePacket) packet;
        byte[] body = basePacket.getBody();
        int bodyLen = 0;
        if (body != null) {
            bodyLen = body.length;
        }

        //总长度是消息头的长度+消息体的长度
        int allLen = BasePacket.HEADER_LENGTH + bodyLen;

        ByteBuffer buffer = ByteBuffer.allocate(allLen);
        buffer.order(groupContext.getByteOrder());

        //写入消息类型
        buffer.put(basePacket.getType());
        //写入消息体长度
        buffer.putInt(bodyLen);

        //写入消息体
        if (body != null) {
            buffer.put(body);
        }
        return buffer;
    }
}
